#ifndef VECTOR_H_INCLUDED
#define VECTOR_H_INCLUDED

#include "Atomic.h"
#include "IteratorForward.h"

namespace CEngine {

template<class Element>
class Vector {
        struct VectorIterator;

    public:

        ///Creates an empty vector. Does not allocate memory.
        Vector(void);

        ///Creates a vector numberOfElements long, elements use a blank constructor.
        Vector(const U64 numberOfElements);

        ///Creates a vector numberOfElements long, elements are all set to defaultValue.
        Vector(const U64 numberOfElements, const Element& defaultValue);

        ///Creates a vector made of the elements between first and last (including first, but not last).
        template<class T>
        Vector(const Iterator<T>& first, const Iterator<T>& last);

        ///Creates a copy of vector. Capacity is equal to size.
        Vector(const Vector& vector);

        ///Copies the contents of vector (destroys all previous elements).
        ///Only increases capacity if needed.
        Vector&
        operator= (const Vector& vector);

        ///Destructor.
        ~Vector(void);

        ///Iterator function. Returns an iterator to the first element in the vector.
        VectorIterator
        begin(void) const;

        ///Iterator function. Returns an iterator to the last element in the vector.
        VectorIterator
        rBegin(void) const;

        ///Iterator function. Returns an iterator to the element after the end of the vector.
        ///Do not dereference.
        VectorIterator
        end(void) const;

        ///Iterator function. Returns an iterator to the element before the start of the vector.
        ///Do not dereference.
        VectorIterator
        rEnd(void) const;

        ///Access function. Returns the element at the front of the vector.
        Element&
        front(void) const;

        ///Access function. Returns the element at the back of the vector.
        Element&
        back(void) const;

        ///Adds element to the end of the Vector.
        ///If the Vector is full capacity is doubled.
        void
        pushBack(const Element& element);

        ///Deletes the last element in the Vector.
        void
        popBack(void);

        ///Inserts element at the given position.
        ///If position >= size, element is added to the end of the vector.
        void
        insert(const Iterator<Element>& position, const Element& element);

        ///Inserts a group of elements all equal to element.
        ///If position >= size, element is added to the end of the vector.
        void
        insert(const Iterator<Element>& position, const U64 numberOfElements, const Element& element);

        ///Deletes the element at position.
        void
        erase(const Iterator<Element>& position);

        ///Deletes every element between first and last (including first but not last).
        ///fails if first > last.
        void
        erase(const Iterator<Element>& first, const Iterator<Element>& last);

        ///Changes the number of elements in the Vector.
        ///New elements are random.
        void
        resize(const U64 numberOfElements);

        ///Changes the number of elements in the Vector.
        ///New elements are equal to element.
        void
        resize(const U64 numberOfElements, const Element& element);

        ///Increases capacity if needed. Will not shrink it.
        void
        reserve(const U64 numberOfElements);

        ///Decreases capacity if needed. Will not grow it.
        void
        shrink(const U64 numberOfElements);

        ///Removes every element from the array. Capacity is not changed.
        void
        clear(void);

        ///Returns if there are any elements in the vector.
        bool
        isEmpty(void) const;

        ///Returns the size of the Vector (in elements).
        U64
        getSize(void) const;

        ///Returns the capacity of the Vector (in elements).
        U64
        getCapacity(void) const;

        ///Returns a pointer to the raw array.
        Element*
        getRawArray(void) const;

    private:

        Element* array;
        U64 size;
        U64 capacity;

        template<class E, class K> friend class Iterator;

        ///Iterator initializer used by the generic Iterator class.
        struct VectorIterator {
            Vector<Element>* basePointer;
            Element* currentPointer;
        };
};

///Is not integrated into Iterator!
template<>
class Vector <bool> {
    public:

        ///Creates an empty vector. Does not allocate memory.
        Vector(void);

        ///Creates a vector numberOfElements long, elements set to false.
        Vector(const U64 numberOfElements);

        ///Creates a vector numberOfElements long, elements are set to defaultValue.
        Vector(const U64 numberOfElements, const bool& defaultValue);

        ///Creates a vector made of the elements between first and last (including first, but not last).
        template<class T>
        Vector(const Iterator<T>& first, const Iterator<T>& last);

        ///Creates a copy of vector. Capacity is equal to size (or rounded up).
        Vector(const Vector& vector);

        ///Copies the contents of vector (destroys all previous elements).
        ///Only increases capacity if needed.
        Vector&
        operator= (const Vector& vector);

        ///Destructor.
        ~Vector(void);

        ///Access function. Returns the elements at the front of the vector.
        bool
        front(void) const;

        ///Access function. Returns the elements at the back of the vector.
        bool
        back(void) const;

        ///Adds element to the end of the Vector.
        ///If the Vector is full capacity is doubled.
        void
        pushBack(const bool& element);

        ///Deletes the last elements in the Vector.
        void
        popBack(void);

        ///Returns the bit at position;
        inline bool
        getBit(const U64 position) const;

        ///Sets the bit at position to set;
        inline void
        setBit(const U64 position, const bool set);

        ///Inserts element at the given position.
        ///If position >= size, element is added to the end of the vector.
        void
        insert(const U64 position, const bool& element);

        ///Inserts a group of elements all equal to element.
        ///If position >= size, element is added to the end of the vector.
        void
        insert(const U64 position, const U64 numberOfElements, const bool& element);

        ///Deletes the element at the given position.
        void
        erase(const U64 position);

        ///Deletes every element between first and last (including first, but not last).
        ///fails if first > last.
        void
        erase(const U64 first, const U64 last);

        ///Changes the number of elements in the Vector.
        ///New elements are false.
        void
        resize(const U64 numberOfElements);

        ///Changes the number of elements in the Vector.
        ///New elements are equal to element.
        void
        resize(const U64 numberOfElements, const bool& element);

        ///Increases capacity if needed. Will not shrink it.
        void
        reserve(const U64 numberOfElements);

        ///Decreases capacity if needed. Will not grow it.
        void
        shrink(const U64 numberOfElements);

        ///Removes every element from the array. Capacity is not changed.
        void
        clear(void);

        ///Returns if there are any elements in the vector.
        bool
        isEmpty(void) const;

        ///Returns the size of the Vector (in elements).
        U64
        getSize(void) const;

        ///Returns the capacity of the Vector (in elements).
        U64
        getCapacity(void) const;

        ///Returns a pointer to the raw array.
        U64*
        getRawArray(void) const;

    private:

        U64* array;
        U64 size;
        U64 capacity;

        void
        shiftBits(const U64 position, U64 sizeOfShift, bool shiftRight);
};

}

#include "VectorCore.h"
//#include "VectorBool.h"

#endif // VECTOR_H_INCLUDED
